package com.hjf.booking.security.authentication;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.hjf.booking.module.user.mapper.UserMapper;
import com.hjf.booking.module.user.po.User;
import com.hjf.booking.security.utils.StringRandomUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * @author hjf
 * @date 2021-03-16 19:57
 */
@Component
public class SelfUserService implements UserDetailsService {

    @Autowired
    RedisTemplate<Object, Object> redisTemplate;

    //token有效期，设为半个钟
    public static final int EXPIRE_TIME = 1800000;

    @Autowired
    UserMapper userMapper;

    /**
     * 根据用户名获取用户信息
     *
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userMapper.selectByName(username);
        if (user == null) {
            throw new UsernameNotFoundException("用户名不存在");
        }
        return org.springframework.security.core.userdetails.User.builder().username(username).password(user.getPassword()).roles("USER").build();
    }

    /**
     * 将用户信息封装成用户认证jwt
     *
     * @param username
     * @return
     */
    public String getUserToken(String username) {
        Date expireTime = new Date(System.currentTimeMillis() + EXPIRE_TIME);
        String salt = getSalt(username);
        String token = JWT.create().withSubject(username)
                .withIssuedAt(new Date())
                .withExpiresAt(expireTime)
                .sign(Algorithm.HMAC256(salt));
        return token;
    }

    /**
     * 获取加密算法密钥
     *
     * @param username
     * @return
     */
    public String getSalt(String username){
        //先从Redis中获取
        String key = "salt" + username;
        Object saltObj = redisTemplate.opsForValue().get(key);
        String salt = "";
        //如果Redis获取密钥失败，从数据库中获取
        if(saltObj == null){
            User user = userMapper.selectByName(username);
            salt = user.getSalt();
        }else {
            salt = String.valueOf(saltObj);
        }
        //如果库里也没，重新生成密钥并将密钥更新至数据库和Redis中
        if(StringUtils.isBlank(salt)){
            salt = StringRandomUtil.generateString(15);
            userMapper.refreshSalt(username,salt);
            redisTemplate.opsForValue().set(key,salt);
        }
        return salt;
    }

    public void createUser(String username, String password) {
        String encryptPwd = SelfPasswordEncod.encode(password);
        /**
         * @todo 保存用户名和加密后密码到数据库
         */
    }

    /**
     * 账户退出，更新用户加密密钥
     *
     * @param username
     */
    public void deleteUserLoginInfo(String username) {
        String key = "salt" + username;
        String salt = StringRandomUtil.generateString(15);
        userMapper.refreshSalt(username,salt);
        redisTemplate.opsForValue().set(key,salt);
    }
}
